#include "TypeDef.h"
#include "include/string.h"
#include <string.h>
#include <stdlib.h>


static int TypeSize[T_SIZE] = {
	sizeof(int8_t),
	sizeof(int16_t),
	sizeof(int32_t),
	sizeof(int64_t),
	sizeof(double),
	sizeof(struct string*)
};

static void *ConstructNumber(void *value,uint8_t type)
{
	void *buf = malloc(TypeSize[type]);
	memcpy(buf,value,TypeSize[type]);
	return buf;
}

static void *ConstructString(void *value,uint8_t type)
{
	string_t str = string_create((const char*)value);
	return (void*)str;
}

static void DestroyNumber(void *value)
{
	free(value);
}

static void DestroyString(void *value)
{
	string_t str = (string_t)value;
	string_destroy(&str);
}

static void GetNumber(struct Type *value,void *out)
{
	memcpy(out,value->data,TypeSize[value->type]);
}

static void GetString(struct Type *value,void *out)
{
	string_t str1 = (string_t)(value->data);
	string_t str2 = string_create(string_c_str(str1));
	memcpy(out,str2,sizeof(string_t));
}

static void SetNumber(struct Type *value,void *in)
{
	memcpy(value->data,in,TypeSize[value->type]);
}

static void SetString(struct Type *value,void *in)
{
	string_t str1 = (string_t)(value->data);
	const char *str2 = in;
	string_assign_cstr(str1,str2);
}

#ifndef CompareNumber
#define CompareNumber(TYPE)\
static int Compare##TYPE(void *ll,void *rr)\
{\
	Type_t l = *(Type_t*)ll;\
	Type_t r = *(Type_t*)rr;\
	TYPE a = *(TYPE*)l->data;\
	TYPE b = *(TYPE*)r->data;\
	if(a == b)\
		return 0;\
	else if(a < b)\
		return -1;\
	return 1;\
}
#endif

CompareNumber(int8_t);
CompareNumber(int16_t);
//CompareNumber(int32_t);
static int Compareint32_t(void *ll,void *rr)
{
	Type_t l = *(Type_t*)ll;
	Type_t r = *(Type_t*)rr;
	int32_t a = *(int32_t*)l->data;
	int32_t b = *(int32_t*)r->data;
	if(a == b)
		return 0;
	else if(a < b)
		return -1;
	return 1;
}
CompareNumber(int64_t);
CompareNumber(double);

static int CompareString(void *ll,void *rr)
{
	Type_t l = (Type_t)ll;
	Type_t r = (Type_t)rr;
	string_t str1 = (string_t)l->data;
	string_t str2 = (string_t)r->data;
	return string_compare(str1,str2);
}


typedef void*(*ConstructFunction)(void*,uint8_t);
typedef void(*DestroyFunction)(void*);
typedef void(*GetFunction)(Type_t,void*);
typedef void(*SetFunction)(Type_t,void*);
typedef int(*CompareFunction)(void*,void*);

static ConstructFunction ConstructFuns[T_SIZE] = 
{
	ConstructNumber,
	ConstructNumber,
	ConstructNumber,
	ConstructNumber,
	ConstructNumber,
	ConstructString,
};

static DestroyFunction DestroyFuns[T_SIZE] = 
{
	DestroyNumber,
	DestroyNumber,
	DestroyNumber,
	DestroyNumber,
	DestroyNumber,
	DestroyString,
};

static SetFunction SetFuns[T_SIZE] = 
{
	SetNumber,
	SetNumber,
	SetNumber,
	SetNumber,
	SetNumber,
	SetString,
};

static GetFunction GetFuns[T_SIZE] = 
{
	GetNumber,
	GetNumber,
	GetNumber,
	GetNumber,
	GetNumber,
	GetString,
};

static CompareFunction CompareFuns[T_SIZE] = 
{
	Compareint8_t,
	Compareint16_t,
	Compareint32_t,
	Compareint64_t,
	Comparedouble,
	CompareString,
};

Type_t CreateType(void *value,uint8_t type)
{
	Type_t t = malloc(sizeof(*t));
	t->type = type;
	t->Get = GetFuns[type];
	t->Set = GetFuns[type];
	t->Compare = CompareFuns[type];
	t->data = ConstructFuns[type](value,type);
	return t;
}

void   DestroyType(Type_t *t)
{
	DestroyFuns[(*t)->type]((*t)->data);
	free(*t);
	*t = 0;
}